﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp_core
{
    public class LockShow
    {
        /*
         锁：我个人的理解，就是资源占用，只允许所占用的线程所有(狭义上),其他线程不能访问和操作，并等待到锁释放才能访问和操作
             
        */

        /// <summary>
        /// 以下演示一个多线程访问同一个资源i的问题
        /// </summary>
        public void Show()
        {
            int i = 0;

            //多线程对单一资源
            //var tasks = new List<Task>();
            foreach (var item in Enumerable.Range(1, 1000))
            {
                var action1 = new Action(() =>
                {
                    i += 1;
                });
                Task.Run(action1);
            }

            Task.WaitAll();
            Console.WriteLine($"i={i}");//结果是小于1000

        }

        public static readonly object _addLock = new object();
        /// <summary>
        /// 多线程对单一资源,进行了锁，变成单线程，谁先拿谁先用，用完释放，给下一个线程访问操作。
        /// </summary>
        public void Show2()
        {
            int i = 0;

            //多线程对单一资源
            //var tasks = new List<Task>();
            foreach (var item in Enumerable.Range(1, 1000))
            {
                var action1 = new Action(() =>
                {
                    lock (_addLock)
                        i += 1;
                });
                Task.Run(action1);
            }

            Task.WaitAll();
            Console.WriteLine($"i={i}");//结果是等于1000

        }




        public static readonly object _ALock = new object();

        public static readonly object _BLock = new object();
        /// <summary>
        /// 令人期待的死锁。
        /// 线程1和线程2
        /// 资源a和资源b
        /// 线程1需要：锁A后锁B
        /// 线程2需要：锁B后锁A
        /// 
        /// 如果线程1拿到了A，同时线程2拿到了B
        /// 线程1要拿B的时候，B给线程2占用，则需要等待线程2释放B
        /// 线程2要拿A的时候，A给线程1占用，则需要等待线程1释放A
        /// 这样2个线程各手里拿着一个锁，眼里又等待对方的锁释放。这样形成的死锁。(典型的死锁)
        /// </summary>
        public void Show3()
        {
            var action1 = new Action(() =>
            {
                lock (_ALock)
                {
                    Console.WriteLine("action1_ALock");
                    Thread.Sleep(100);
                    lock (_BLock)
                    {
                        Console.WriteLine("action1_BLock");
                    }
                }
            });
            var task1= Task.Run(action1);

            var action2 = new Action(() =>
            {
                lock (_BLock)
                {
                    Console.WriteLine("action2_BLock");
                    Thread.Sleep(100);
                    lock (_ALock)
                    {
                        Console.WriteLine("action2_ALock");
                    }
                }
            });
            var task2= Task.Run(action2);

            Task.WaitAll(new Task[2] { task1,task2});
        }
    }
}
